﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.VisualBasic.FileIO;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using XL.Crawler.Api;
using XL.Crawler.Core.Crawlers;

namespace XL.Crawler.Core
{
    /// <summary>
    /// 爬虫容器扩展
    /// </summary>
    public static class ServiceCollectionCrawlerExtensions
    {
        /// <summary>
        /// 添加爬虫业务后台任务
        /// </summary>
        /// <see cref="CrawlerTaskBackgroundService"/>
        /// <returns></returns>
        public static IServiceCollection AddCrawlerHostedService(this IServiceCollection services)
        {

            services.ConfigureCrawler();
            services.AddCrawlers();
            services.AddHostedService<CrawlerTaskBackgroundService>();
            return services;
        }

        /// <summary>
        /// 添加爬虫业务至容器
        /// </summary>
        /// <param name="services">服务容器</param>
        private static IServiceCollection AddCrawlers(this IServiceCollection services)
        {
            var allCrawlerTypes = ScanCrawlerTypes();
            foreach (Type crawlerType in allCrawlerTypes)
            {
                services.AddTransient(typeof(ICrawler), crawlerType);
            }
            return services;
        }
        /// <summary>
        /// 配置Json
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        private static IServiceCollection ConfigureCrawler(this IServiceCollection services)
        {
            IConfiguration? configuration = null;
            HostBuilderContext? hostBuilderContext = services.GetImplementationInstance<HostBuilderContext>();
            if (hostBuilderContext?.Configuration != null)
            {
                configuration = hostBuilderContext.Configuration;
            }
            else
            {
                configuration = services.GetImplementationInstance<IConfiguration>();
            }
            if (configuration is not null)
            {
                services.Configure<CrawlerOptions>(x =>
                {
                    x.Url = configuration["Crawler:Url"] ?? string.Empty;

                });
            }
            return services;

        }

        /// <summary>
        /// 扫描程序集,查找出实现ICrawler的类
        /// </summary>
        /// <returns></returns>
        private static List<Type> ScanCrawlerTypes()
        {
            string[] allDlls = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll");
            IEnumerable<Assembly> allAssemblies = allDlls.Select(assemblyFile => Assembly.Load(AssemblyName.GetAssemblyName(assemblyFile)));
            var allCrawlerTypes = allAssemblies.SelectMany(assembly => assembly.GetTypes())
                                               .Where(type => typeof(ICrawler).IsAssignableFrom(type))
                                               .Where(type => !type.IsInterface)
                                               .Where(type => !type.IsAbstract)
                                               .ToList();

            return allCrawlerTypes;


        }
        /// <summary>
        /// 获取业务之实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="services"></param>
        /// <returns></returns>
        private static T? GetImplementationInstance<T>(this IServiceCollection services)
        {
            var descriptor = services.FirstOrDefault(d => d.ServiceType == typeof(T));
            if (descriptor != null)
            {
                var instance = descriptor.IsKeyedService ? descriptor.KeyedImplementationInstance : descriptor.ImplementationInstance;
                if (instance is null)
                {
                    instance = descriptor.ImplementationFactory!(services.BuildServiceProvider());
                    return (T?)instance;
                }
                return (T?)instance;
            }
            return default(T?);
        }
    }
}
